/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package proy4sistdistribuidos.control;

import java.awt.image.BufferedImage;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.util.ArrayList;
import java.util.Random;

import javax.imageio.ImageIO;

import org.simpleframework.xml.Serializer;
import org.simpleframework.xml.core.Persister;

import proy4sistdistribuidos.modelo.ContenedorImagenTomada;
import proy4sistdistribuidos.modelo.DatosImagenTomada;
import proy4sistdistribuidos.modelo.ImagenTomada;
import proy4sistdistribuidos.modelo.ListaDatosImagenTomada;
import proy4sistdistribuidos.modelo.VariablesEstaticas;

/**
 *
 * @author Carlos Diaz Maya, Juan Felipe Garcia
 */
public class ProtocoloServidorProy4SistDistribuidosEscritorio {

    private static final int INICIAL = 0;
    private static final int ENVIARFOTO = 1;
    private static final int OBTENERINFOFOTOSTOMADASENSITIO = 2;
    private static final int OBTENERFOTOPORNOMBRE = 3;
    private static final int OBTENERINFOFOTOPORFOTODADA = 4;
    private static final int FINAL = 5;
    private int estado = INICIAL;
    
    public static final double cotaInferior = 0.5d;
    public static final double cotaSuperior = 1.5d;

    public String procesarEntrada(String comandoEntrada) throws Exception {
        String salida = null;
        if (estado == INICIAL) {

            if (comandoEntrada != null && comandoEntrada.length() > 1) {
                if (comandoEntrada.startsWith("EnviarFoto_")) {
                    estado = ENVIARFOTO;
                } else if (comandoEntrada.startsWith("ObtenerInfoFotosTomadasEnSitio_")) {
                    estado = OBTENERINFOFOTOSTOMADASENSITIO;
                } else if (comandoEntrada.startsWith("ObtenerFotoPorNombre_")) {
                	estado = OBTENERFOTOPORNOMBRE;
                } else if (comandoEntrada.startsWith("ObtenerInfoFotoPorFotoDada_")){
                	estado = OBTENERINFOFOTOPORFOTODADA;                	
                } else {
                    salida = "";
                    estado = FINAL;
                }
            } else {
                salida = "";
                estado = FINAL;
            }
        }

        if (estado == ENVIARFOTO) {
        	 String aux = "EnviarFoto_";
             String infoFotoXMLRaw = null;
             String comm = comandoEntrada.substring(aux.length());
             comm=comm.replaceAll("_CHARRO2_", "\r\n");
             comm=comm.replaceAll("_CHARRO_", "\n");
             infoFotoXMLRaw = comm;
             
             File carpetaTemp1 = new File(VariablesEstaticas.rutaTemporales);
             if(!carpetaTemp1.exists()){
            	 carpetaTemp1.mkdirs();
             }
             
             ContenedorImagenTomada datosImagen = null;
             
             synchronized (this) {	
	             File archivoTemp1 = new File(VariablesEstaticas.rutaTemporales, "archTemp.xml");
	             if(archivoTemp1.exists()){
	            	 archivoTemp1.delete();
	            	 archivoTemp1.createNewFile();
	             } else {
	            	 archivoTemp1.createNewFile();
	             }
	             
	             FileWriter fw = new FileWriter(archivoTemp1);
	             fw.write(infoFotoXMLRaw);
	             fw.close();
	             
	             Serializer serializer = new Persister();
	             File source = new File(VariablesEstaticas.rutaTemporales, "archTemp.xml");
	
	             datosImagen = serializer.read(ContenedorImagenTomada.class, source);
             }
             
             //Se obtiene el contenido de la imagen
             ImagenTomada imgTom = datosImagen.getContenidoImagen();
             DatosImagenTomada datosImgTom = datosImagen.getDatosImagen();
             
             ByteArrayInputStream bais = new ByteArrayInputStream(imgTom.getDatosImagen());
             
             BufferedImage image = ImageIO.read(bais);
             
             
             //Se obtiene el color promedio y el tamanho
             int ancho = image.getWidth();
             int alto = image.getHeight();
             long suma = 0l;
             long cant = 0;
             for(int i = 0; i<ancho; i++){
                 for(int j = 0 ; j<alto; j++){
                     int pix = image.getRGB(i, j);
                     suma += new Integer(pix).longValue();
                     cant++;
                 }
             }
             long colorPromedio = 0l;
             if(cant>0){
                 colorPromedio = suma/cant;
             } else {
                 colorPromedio = -1l;
             }
             
             Long tamArchivoBytes = new Integer(imgTom.getDatosImagen().length).longValue();
             
             datosImgTom.setTamanho(tamArchivoBytes.toString());
             datosImgTom.setColorPromedio(new Long(colorPromedio).toString());
             
             datosImagen.setDatosImagen(datosImgTom);
             
             File carpetaXML = new File(VariablesEstaticas.rutaFotos);
             if(!carpetaXML.exists()){
            	 carpetaXML.mkdirs();
             }
             
             File archivoXMLAGuardar = new File(VariablesEstaticas.rutaFotos, datosImgTom.getNombre()+".xml");
             if(archivoXMLAGuardar.exists()) {
            	 archivoXMLAGuardar.delete();
            	 archivoXMLAGuardar.createNewFile();
             } else {
            	 archivoXMLAGuardar.createNewFile();
             }
             
             salida = "OK";
             
            //Se guarda en disco la imagen recibida
            Serializer serializador = new Persister();
 			serializador.write(datosImagen, archivoXMLAGuardar);
 			 			
            estado = FINAL;
        }
        
        if (estado == OBTENERINFOFOTOSTOMADASENSITIO) {
        	String aux = "ObtenerInfoFotosTomadasEnSitio_";
            String infoNombreUbicacion = null;
            String comm = comandoEntrada.substring(aux.length());
            comm=comm.replaceAll("_CHARRO2_", "\r\n");
            comm=comm.replaceAll("_CHARRO_", "\n");
            infoNombreUbicacion = comm;
            
            File carpetaDefinitiva = new File(VariablesEstaticas.rutaFotos);
            
            if(!carpetaDefinitiva.exists()){
            	carpetaDefinitiva.mkdirs();
            }
            
            File[] listaImagenes = carpetaDefinitiva.listFiles();
            
            
            Serializer serializer = new Persister();
            ListaDatosImagenTomada datosImagenes = null;
                        
            if(listaImagenes!=null){
            	datosImagenes = new ListaDatosImagenTomada();
            	ArrayList<DatosImagenTomada> lista = new ArrayList<DatosImagenTomada>(); 
            	datosImagenes.setLista(lista);
            	for(File archivoImagen : listaImagenes) {
            		try {
            			ContenedorImagenTomada contenedorImgTom = serializer.read(ContenedorImagenTomada.class, archivoImagen);
            			if(contenedorImgTom.getDatosImagen()!=null &&
            			   contenedorImgTom.getDatosImagen().getUbicacion()!=null &&
            			   contenedorImgTom.getDatosImagen().getUbicacion().equals(infoNombreUbicacion)){
            				datosImagenes.getLista().add(contenedorImgTom.getDatosImagen());
            			}            			
            		} catch(Exception f) {
            			f.printStackTrace();
            		}
            	}
            }
        	
            if(datosImagenes==null || datosImagenes.getLista()==null || datosImagenes.getLista().size()==0){
            	 salida = "";
            } else {
            	//Se serializa la lista de datos de imagenes
            	 File carpetaTemp1 = new File(VariablesEstaticas.rutaTemporales);
                 if(!carpetaTemp1.exists()){
                	 carpetaTemp1.mkdirs();
                 }    
            	
            	File archivoASerializar = new File(VariablesEstaticas.rutaTemporales, "archTemp4.xml");
            	
            	if(archivoASerializar.exists()){
            		archivoASerializar.delete();
            		archivoASerializar.createNewFile();
            	} else {
            		archivoASerializar.createNewFile();
            	}
            	
            	serializer.write(datosImagenes, archivoASerializar);
            	
            	
            	String cadena = "";
    			FileReader frXML = new FileReader(archivoASerializar);
    			BufferedReader brXML = new BufferedReader(frXML);
    			String linea = "";
    			while ((linea = brXML.readLine())!=null) {
    				cadena += linea;
    			}
    			brXML.close();
    			frXML.close();
    			
    			cadena = cadena.replaceAll("\r\n", "_CHARRO2_");
                cadena = cadena.replaceAll("\n", "_CHARRO_");
                
                salida = cadena;
            }
            estado = FINAL;
        }
        
        if (estado == OBTENERFOTOPORNOMBRE) {
        	String aux = "ObtenerFotoPorNombre_";
            String infoNombreFoto = null;
            String comm = comandoEntrada.substring(aux.length());
            comm=comm.replaceAll("_CHARRO2_", "\r\n");
            comm=comm.replaceAll("_CHARRO_", "\n");
            infoNombreFoto = comm;
            
            File archFoto = new File(VariablesEstaticas.rutaFotos, infoNombreFoto+".xml");
            
            if(!archFoto.exists()){
            	salida = "";
            } else {
            	//Se retorna el contenido XML del archivo, reemplazando saltos de linea por caracteres
            	String cadena = "";
    			FileReader frXML = new FileReader(archFoto);
    			BufferedReader brXML = new BufferedReader(frXML);
    			String linea = "";
    			while ((linea = brXML.readLine())!=null) {
    				cadena += linea;
    			}
    			brXML.close();
    			frXML.close();
    			
    			cadena = cadena.replaceAll("\r\n", "_CHARRO2_");
                cadena = cadena.replaceAll("\n", "_CHARRO_");
                
                salida = cadena;
                
                
            }
            
            
            estado = FINAL;
        }
        
        if (estado == OBTENERINFOFOTOPORFOTODADA) {
        	String aux = "ObtenerInfoFotoPorFotoDada_";
            String datoFoto = null;
            String comm = comandoEntrada.substring(aux.length());
            comm=comm.replaceAll("_CHARRO2_", "\r\n");
            comm=comm.replaceAll("_CHARRO_", "\n");
            datoFoto = comm;
            
            ImagenTomada imgTom = null;
            
            File carpetaTemp1 = new File(VariablesEstaticas.rutaTemporales);
            if(!carpetaTemp1.exists()){
           	 carpetaTemp1.mkdirs();
            }
                    
            synchronized (this) {	
   	             File archivoTemp2 = new File(VariablesEstaticas.rutaTemporales, "archTemp2.xml");
   	             if(archivoTemp2.exists()){
   	            	 archivoTemp2.delete();
   	            	 archivoTemp2.createNewFile();
   	             } else {
   	            	 archivoTemp2.createNewFile();
   	             }
   	             
   	             FileWriter fw = new FileWriter(archivoTemp2);
   	             fw.write(datoFoto);
   	             fw.close();
   	             
   	             Serializer serializer = new Persister();
   	             File source = new File(VariablesEstaticas.rutaTemporales, "archTemp2.xml");
   	
   	             imgTom = serializer.read(ImagenTomada.class, source);
            }
            
            
            ByteArrayInputStream bais = new ByteArrayInputStream(imgTom.getDatosImagen());
            
            BufferedImage image = ImageIO.read(bais);
            
            
            //Se obtiene el color promedio y el tamanho
            int ancho = image.getWidth();
            int alto = image.getHeight();
            long suma = 0l;
            long cant = 0;
            for(int i = 0; i<ancho; i++){
                for(int j = 0 ; j<alto; j++){
                    int pix = image.getRGB(i, j);
                    suma += new Integer(pix).longValue();
                    cant++;
                }
            }
            long colorPromedio = 0l;
            if(cant>0){
                colorPromedio = suma/cant;
            } else {
                colorPromedio = -1l;
            }
            
            Long tamArchivoBytes = new Integer(imgTom.getDatosImagen().length).longValue();
            
            //Ahora se busca en todos los archivos el archivo que tenga el mejor indice de similitud
            ContenedorImagenTomada archivoSeleccionado = null;
            
            
            File carpetaDefinitiva = new File(VariablesEstaticas.rutaFotos);
            
            if(!carpetaDefinitiva.exists()){
            	carpetaDefinitiva.mkdirs();
            }
            
            File[] listaImagenes = carpetaDefinitiva.listFiles();
            
            
            Serializer serializer = new Persister();            
            if(listaImagenes!=null){
	            for(File archivoImagen:listaImagenes){ 
	            	try{            		    	
	            		ContenedorImagenTomada contenedorImgTom = serializer.read(ContenedorImagenTomada.class, archivoImagen);
	            		
	            		DatosImagenTomada ad = contenedorImgTom.getDatosImagen();
	            		
	            		
	            	
		             if(ad!=null && ad.getColorPromedio() != null && ad.getTamanho() != null) {
		                Long promedioK = Long.parseLong(ad.getColorPromedio());
		                Long tamanhoK = Long.parseLong(ad.getTamanho());
		
		                Double funcDistancia = ((new Long(colorPromedio).doubleValue() / promedioK.doubleValue()) + (tamArchivoBytes.doubleValue() / tamanhoK.doubleValue())) / 2;
		
		                if (funcDistancia.doubleValue() >= cotaInferior && funcDistancia.doubleValue() <= cotaSuperior) {
		                    if(archivoSeleccionado==null){
		                        archivoSeleccionado = contenedorImgTom;
		                    } else {
		                        Long promedioAdv2 = Long.parseLong(archivoSeleccionado.getDatosImagen().getColorPromedio());
		                        Long tamanhoAdv2 = Long.parseLong(archivoSeleccionado.getDatosImagen().getTamanho());
		                        Double funcDistanciaAdv2 = ((new Long(colorPromedio).doubleValue() / promedioAdv2.doubleValue()) + (tamArchivoBytes.doubleValue() / tamanhoAdv2.doubleValue())) / 2;
		                        Double cercaniaAUnoAdv2 = Math.abs(funcDistanciaAdv2-1d);
		                        Double cercaniaAUnoImgSel = Math.abs(funcDistancia-1d);
		
		                        if(cercaniaAUnoImgSel<=cercaniaAUnoAdv2){
		                           archivoSeleccionado = contenedorImgTom;
		                        }
		                    }
		                    System.out.println("color: "+ad.getColorPromedio() + " tamaño:" +ad.getTamanho());
		                }
		             }
		            } catch(Exception f){
		            	f.printStackTrace();
		            }
	            }
            }
            
            		
            if(archivoSeleccionado==null){           		
            	salida = "";
            } else {
            	synchronized(this){
	            	//Se serializa el objeto de datos de imagen en formato XML, reemplazando saltos de linea por caracteres
	            	DatosImagenTomada datosASerializar = archivoSeleccionado.getDatosImagen();
	            	
	            	File archivoASerializar = new File(VariablesEstaticas.rutaTemporales, "archTemp3.xml");
	            	
	            	if(archivoASerializar.exists()){
	            		archivoASerializar.delete();
	            		archivoASerializar.createNewFile();
	            	} else {
	            		archivoASerializar.createNewFile();
	            	}
	            	
	            	serializer.write(datosASerializar, archivoASerializar);
	            	
	            	
	            	String cadena = "";
	    			FileReader frXML = new FileReader(archivoASerializar);
	    			BufferedReader brXML = new BufferedReader(frXML);
	    			String linea = "";
	    			while ((linea = brXML.readLine())!=null) {
	    				cadena += linea;
	    			}
	    			brXML.close();
	    			frXML.close();
	    			
	    			cadena = cadena.replaceAll("\r\n", "_CHARRO2_");
	                cadena = cadena.replaceAll("\n", "_CHARRO_");
	                
	                salida = cadena;
            	}
            }
            estado = FINAL;
        }
        

        if (estado == FINAL) {
            estado = INICIAL;
        }
        return salida;
    }
}